#include <iostream>
#include <string>
#include <unistd.h>
#include <cstring>
#include <cerrno>
#include <sys/types.h>
#include <sys/wait.h>

// 获取子进程其他动态信息
std::string getOtherMessage()
{
    static int cnt = 0;
    cnt++;
    std::string messagecnt = std::to_string(cnt);

    pid_t id = getpid();
    std::string messageid = std::to_string(id);

    std::string message = "messagecnt: ";
    message += messagecnt;
    message += " my pid is: ";
    message += messageid;

    return message;
}

// 子进程写入
void childProcessWrite(int wfd)
{
    std::string message = "father, I am your child process!";
    while(true)
    {
        std::string info = message + getOtherMessage();
        // 这里使用string的接口size()写入时是不包含'\0'的，没有必要
        write(wfd, info.c_str(), info.size()); 

        sleep(2);
    }
}

// 父进程读
void fatherProcessRead(int rfd)
{
    char inbuffer[512];
    while(true)
    {
        ssize_t n = read(rfd, inbuffer, sizeof(inbuffer) - 1); // 读的时候也不用读'\0'
        if(n > 0)
        {
            inbuffer[n] = 0; // 相当于 '\0'了
            std::cout << "father get message: " << inbuffer << std::endl << std::endl;
        }
        else if(n == 0)
        {
            // 表示写端直接关闭了，读到了文件结尾
            std::cout << "wfd close, father get return val: " << n << std::endl;
            break;
        }
        else
        {
            // 读失败了
            std::cout << "read error" << std::endl;
        }
    }
}


int main()
{
    // 1.创建管道
    int pipefd[2];
    int n = pipe(pipefd);
    if(n != 0) 
    {
        std::cerr << "error: " << strerror(errno) << std::endl; 
        return 1;
    }

    // 验证一下文件分配
    std::cout << "pipefd[0]: " << pipefd[0] << ", pipefd[1]: " << pipefd[1] << std::endl;
    sleep(1);

    // 2.创建子进程
    pid_t id = fork();
    if(id == 0)
    {
        std::cout << "子进程关闭不需要的fd了, 准备发消息了" << std::endl;
        sleep(1);

        // child --- write
        // 3.关闭不需要的fd
        close(pipefd[0]);
        childProcessWrite(pipefd[1]);
        close(pipefd[1]);

        exit(0);
    }

    std::cout << "父进程关闭不需要的fd了, 准备收消息了" << std::endl;
    sleep(1);

    // father --- read
    // 3.关闭不需要的fd
    close(pipefd[1]);
    fatherProcessRead(pipefd[0]);
    close(pipefd[0]);

    // 等待子进程退出
    pid_t rid = waitpid(id, nullptr, 0);
    if(rid > 0)
    {
        std::cout << "wait child quit success!" << std::endl;
    }

    return 0;
}
